#include "fenetreopengl.h"


//--------------------- Constructeurs et destructeur -------------------
/* ****************************************************************
 * Constructeur de la fenetre
 * @param framePerSecond : temps de rafraichissement de
                           la fenetre (images par seconde)
 * @param parent : QWidget parent de cette fenêtre
 * @param name : nom de la fenetre
 * **************************************************************** */
FenetreOpengl::FenetreOpengl(int framesPerSecond, QWidget *parent, char *name)
    : QGLWidget(parent)
{
    //On initialise la scène
    _scene = new Scene();

    //On donne un titre à la fenêtre
    setWindowTitle(QString::fromUtf8(name));

    //On définit notre timer pour le rafraichissement de notre fenêtre
    if(framesPerSecond == 0)
        _timer = NULL;
    else
    {
        int seconde = 1000; // 1 seconde = 1000 ms
        int intervale = seconde / framesPerSecond;
        _timer = new QTimer(this);
        connect(_timer, SIGNAL(timeout()), this, SLOT(timerTermine()));
        _timer->start(intervale);
    }
}

/* ****************************************************************
 * Destructeur de la fenetre
 * **************************************************************** */
FenetreOpengl::~FenetreOpengl()
{
    delete _timer;
    delete _scene;
}

//----------------------------------------------------------------------
//--------------------- Méthodes ---------------------------------------

/* ****************************************************************
 * Fonction permettant d'initialiser notre fenetre opengl
 * **************************************************************** */
void FenetreOpengl::initializeGL()
{
    glShadeModel(GL_SMOOTH);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glEnable(GL_LIGHTING);


    //On initialise une scene
    Point* p1 = new Point(-1.0, -1.0, -1.0);
    Point* p2 = new Point(1.0, -1.0, -1.0);
    Point* p3 = new Point(1.0, 1.0, -1.0);
    Point* p4 = new Point(-1.0, 1.0, -1.0);
    Point* p5 = new Point(-1.0, -1.0, 1.0);
    Point* p6 = new Point(1.0, -1.0, 1.0);
    Point* p7 = new Point(1.0, 1.0, 1.0);
    Point* p8 = new Point(-1.0, 1.0, 1.0);


    //Face de devant
    Face* face1 = new Face();
    Sommet* s1 = new Sommet(*p1, 0.0, 0.0);
    Sommet* s2 = new Sommet(*p2, 1.0, 0.0);
    Sommet* s3 = new Sommet(*p3, 1.0, 1.0);
    Sommet* s4 = new Sommet(*p4, 0.0, 1.0);
    face1->ajouterSommet(*s1);
    face1->ajouterSommet(*s2);
    face1->ajouterSommet(*s3);
    face1->ajouterSommet(*s4);

    //Face de droite
    Face* face2 = new Face();
    face2->ajouterSommet(*(new Sommet(*p3, 0.0, 0.0)));
    face2->ajouterSommet(*(new Sommet(*p2, 1.0, 0.0)));
    face2->ajouterSommet(*(new Sommet(*p6, 1.0, 1.0)));
    face2->ajouterSommet(*(new Sommet(*p7, 0.0, 1.0)));

    //Face de derriere
    Face* face3 = new Face();
    face3->ajouterSommet(*(new Sommet(*p7, 0.0, 0.0)));
    face3->ajouterSommet(*(new Sommet(*p6, 1.0, 0.0)));
    face3->ajouterSommet(*(new Sommet(*p5, 1.0, 1.0)));
    face3->ajouterSommet(*(new Sommet(*p8, 0.0, 1.0)));

    //Face de gauche
    Face* face4 = new Face();
    face4->ajouterSommet(*(new Sommet(*p1, 0.0, 0.0)));
    face4->ajouterSommet(*(new Sommet(*p4, 1.0, 0.0)));
    face4->ajouterSommet(*(new Sommet(*p8, 1.0, 1.0)));
    face4->ajouterSommet(*(new Sommet(*p5, 0.0, 1.0)));

    //Face de dessus
    Face* face5 =new Face();
    face5->ajouterSommet(*(new Sommet(*p4, 0.0, 0.0)));
    face5->ajouterSommet(*(new Sommet(*p3, 1.0, 0.0)));
    face5->ajouterSommet(*(new Sommet(*p7, 1.0, 1.0)));
    face5->ajouterSommet(*(new Sommet(*p8, 0.0, 1.0)));

    //Face de dessous
    Face* face6 = new Face();
    face6->ajouterSommet(*(new Sommet(*p1, 0.0, 0.0)));
    face6->ajouterSommet(*(new Sommet(*p5, 1.0, 0.0)));
    face6->ajouterSommet(*(new Sommet(*p6, 1.0, 1.0)));
    face6->ajouterSommet(*(new Sommet(*p2, 0.0, 1.0)));

    //On calcule le normales
    face1->calculerNormale();
    face2->calculerNormale();
    face3->calculerNormale();
    face4->calculerNormale();
    face5->calculerNormale();
    face6->calculerNormale();


    QList<Face*> faces;
    faces.push_back(face1);
    faces.push_back(face2);
    faces.push_back(face3);
    faces.push_back(face4);
    faces.push_back(face5);
    faces.push_back(face6);

    //Premier objet
    //HTexture* texture = new HTexture("woodBox.bmp");
    Materiaux* materiau = new Materiaux();
    //ObjetScene* objetScene = new ObjetScene(faces, *texture, *(new Materiaux()));

    //Deuxieme objet
    HTextureCouleur* textureCouleur = new HTextureCouleur("woodBox.bmp", 0.0, 1.0, 1.0);
    ObjetScene* os2 = new ObjetScene(faces, *textureCouleur, *materiau);
    //os2->ajouterTransformation(*(new Rotation(30, 1.0, 0.0, 1.0)));
    //os2->ajouterTransformation(*(new Translation(0.0, -2.0, 0.0)));
    //os2->ajouterTransformation(*(new Scale(0.2, 0.5, 0.6)));

    QList<ObjetScene*> listeObjets;
    //listeObjets.push_back(objetScene);
    listeObjets.push_back(os2);

    _scene = new Scene(listeObjets);
    
    QString mw_cheminExecutable = QCoreApplication::applicationDirPath();
    QString cheminMaillage= mw_cheminExecutable + "/ressources/maillages/buddha.off";

    ObjetScene* objet3 = &GestionnaireMaillages::chargerFichierOFF(cheminMaillage);
    objet3->ajouterTransformation((*(new Translation(2.5, -2.0, 0.0))));
    //objet3->ajouterTransformation(*(new Scale(3.0, 3.0, 3.0)));

    objet3->getMateriau().setBrillanceSpeculaire(100.0f);
    objet3->getMateriau().setCouleurAmbiante(0, 0, 0, 1);
    objet3->getMateriau().setCouleurDiffuse(0.1, 0.5, 0.8, 1.0);
    objet3->getMateriau().setCouleurSpeculaire(1,1,1,1);

    _scene->ajouterObjetScene(*objet3);


    GestionnaireLumieres::getInstance().getLumiere(0).enable();
    GestionnaireLumieres::getInstance().getLumiere(0).setPositionLumiere(50.0, 0.0, -10.0, 1.0);
    GestionnaireLumieres::getInstance().getLumiere(0).setCouleurAmbiante(0, 0, 0, 1);
    GestionnaireLumieres::getInstance().getLumiere(0).setCouleurDiffuse(1,1,1,1);
    GestionnaireLumieres::getInstance().getLumiere(1).enable();
    GestionnaireLumieres::getInstance().getLumiere(1).setPositionLumiere(0.0, 10.0, -10, 1.0);
    GestionnaireLumieres::getInstance().getLumiere(1).setCouleurAmbiante(0.0, 0.0, 0.0, 1.0);
    //GestionnaireLumieres::getInstance().getLumiere(1).setCouleurDiffuse(1.0, 0.0, 1.0, 1.0);


    Habillage* tex2;
    ObjetScene* os_copie;
    Scene* scene_copie;

   {
    std::ofstream ofs("s1.scene");
    boost::archive::text_oarchive oa(ofs);
    oa << _scene;
    }
    /*{
    std::ifstream ifs("/home/etudiant/Bureau/svn/trunk/PROJET_SI/ressources/sauvegarde/ss");
    boost::archive::text_iarchive ia(ifs);


    ia >> _scene;
    }
*/

}

/* ****************************************************************
 * Fonction permettant de redimensionner correctement
 * notre fenêtre opengl
 * @param width : nouvelle longueur de la fenêtre
 * @param height : nouvelle hauteur de la hauteur
 * **************************************************************** */
void FenetreOpengl::resizeGL(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

/* ****************************************************************
 * Fonction de dessin
 * **************************************************************** */
void FenetreOpengl::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glPushMatrix();
        _scene->dessiner();
    glPopMatrix();
}

/* ****************************************************************
 * Fonction récupérant l'évènement de l'appuie d'une touche sur le clavier
 * @param keyEvent : touche pressée
 * **************************************************************** */
void FenetreOpengl::keyPressEvent( QKeyEvent *keyEvent )
{
    GLfloat pas = 0.5;
    switch(keyEvent->key())
    {
        case Qt::Key_Z : this->_scene->getCamera().avancerZ(pas); break;
        case Qt::Key_S : this->_scene->getCamera().avancerZ(-pas); break;
        case Qt::Key_Q : this->_scene->getCamera().avancerX(-pas); break;
        case Qt::Key_D : this->_scene->getCamera().avancerX(pas); break;
        case Qt::Key_A : this->_scene->getCamera().avancerY(pas); break;
        case Qt::Key_E : this->_scene->getCamera().avancerY(-pas); break;

        //Pour gérer le regard
        case Qt::Key_Up : this->_scene->getCamera().bougerRegardY(-pas); break;
        case Qt::Key_Down : this->_scene->getCamera().bougerRegardY(pas); break;
        case Qt::Key_Right : this->_scene->getCamera().bougerRegardX(pas); break;
        case Qt::Key_Left : this->_scene->getCamera().bougerRegardX(-pas); break;
    }
}

/* ****************************************************************
 * Fonction récupérant l'évènement du clic de la souris
 * @param mouseEvent : Evenement de la souris
 * **************************************************************** */
void FenetreOpengl::mousePressEvent(QMouseEvent *mouseEvent)
{
    this->setFocus();

}

//----------------------------------------------------------------------

//--------------------- Slots  -----------------------------------------

/* ****************************************************************
 * Slot permettant de récupérer l'évènement du timer pour rafraichir la fenetre
 * **************************************************************** */
void FenetreOpengl::timerTermine()
{
    updateGL();
}

//----------------------------------------------------------------------

//--------------------- Accesseurs -------------------------------------

/* ****************************************************************
 * Accesseur sur la scène
 * @return scene : la scene de la fenetre
 * **************************************************************** */
Scene& FenetreOpengl::getScene()
{
    return *_scene;
}

/* ****************************************************************
 * Setteur sur la scène
 * @param scene : scene à affecter
 * **************************************************************** */
void FenetreOpengl::setScene(Scene& scene)
{
    _scene = &scene;
}

//----------------------------------------------------------------------
//--------------------- Surcharge des opérateurs -----------------------

//----------------------------------------------------------------------


